import React, {
  PropsWithChildren,
  ReactNode,
  useMemo,
  RefObject,
  useEffect,
  useState,
  useRef,
} from 'react';
import styled, { css, CSSProperties } from 'styled-components';
import { color, typography } from '../shared/global';
import { darken, rgba, opacify } from 'polished';
import { easing, modalOpenAnimate, modalCloseAnimate } from '../shared/animation';
import { useStateAnimation } from '../modal';
import Button from '../button';
import {
  CalendarWarpper,
  tableItemStyle,
  CalendarHeadItem,
  CalendarDate,
  CalendarDateRow,
  CalendarHeadWrapper,
  btnStyle,
  IconWrapper,
  BtnDiv,
  MonthItem,
  MonthWrapper,
  Bwrapper,
  CalendarIcon,
  DatePickerWrapper,
} from './styleComponents';
import { Icon } from '../icon';

export function useClickOutside(ref: RefObject<HTMLElement>, handler: Function) {
  useEffect(() => {
    const listener = (event: MouseEvent) => {
      if (!ref.current || ref.current.contains(event.target as Node)) {
        return;
      }
      handler(event);
    };
    window.addEventListener('click', listener);
    return () => window.removeEventListener('click', listener);
  }, [ref, handler]);
}

// 获取当月的日期数据
const getDateData = function (year: number, month: number, day: number): DateItem[][] {
  const firstDay = new Date(year, month, 1);
  let weekDay = firstDay.getDay();
  weekDay = weekDay === 0 ? 7 : weekDay;
  const dayMillSec = 60 * 60 * 24 * 1000;
  let start = firstDay.getTime() - weekDay * dayMillSec;

  let arr: DateItem[] = [];
  for (let i = 0; i < 42; i++) {
    let current = new Date(start + i * dayMillSec);
    let onMonth = isCurrentMonth(current, year, month);
    arr.push({
      day: current.getDate(),
      isonMonth: onMonth,
      isonDay: isCurrentDay(current, day, onMonth),
      origin: current,
    });
  }
  let k = -1;
  return Array.from({ length: 6 }, () => {
    k++;
    return arr.slice(k * 7, (k + 1) * 7);
  });
};

const getYearMonthDay = function (date: number): calDataType {
  let tmp = new Date(date);
  return [tmp.getFullYear(), tmp.getMonth(), tmp.getDate()];
};

const changeCalData = function (sign: number, calData: calDataType): calDataType {
  const oldDate = new Date(calData[0], calData[1]);
  const newDate = oldDate.setMonth(oldDate.getMonth() + sign);
  return getYearMonthDay(newDate);
};

const changeCalYear = function (sign: number, calData: calDataType) {
  const oldDate = new Date(calData[0], calData[1]);
  const newDate = oldDate.setFullYear(oldDate.getFullYear() + sign);
  return getYearMonthDay(newDate);
};

const getStartYear = function (calData: calDataType) {
  return calData[0] - (calData[0] % 10);
};

const generateDate = (calData: calDataType) => {
  return `${calData[0]}-${calData[1] + 1}-${calData[2]}`;
};

// 日期校验 用于日期回显
const validateDate = (value: string) => {
  let reg = /^(\d{4})-(\d{1,2})-(\d{1,2})$/;
  if (reg.exec(value)) {
    return true;
  } else {
    return false;
  }
};

type calDataType = [number, number, number];

type DatePickerProps = {
  /**日期选择的回调 */
  callback?: (v: string) => void;
  /** 动画速度 */
  delay?: number;
  /** 初始值 */
  initDate?: string;
  /** 外层样式 */
  style?: CSSProperties;
  /** 外层类名 */
  classname?: string;
};

export interface DateItem {
  day: number;
  isonMonth: boolean;
  isonDay: boolean;
  origin: Date;
}

type modeType = 'date' | 'month' | 'year';

// 是否是当前月份
const isCurrentMonth = function (current: Date, year: number, month: number): boolean {
  return current.getFullYear() === year && current.getMonth() === month;
};

// 是否是当天
const isCurrentDay = function (current: Date, day: number, onMonth: boolean) {
  return current.getDate() === day && onMonth;
};

export function DatePicker(props: PropsWithChildren<DatePickerProps>) {
  const { callback, style, classname, initDate, delay } = props;
  const [show, setShow] = useState(false);
  const [calData, setCalData] = useState<calDataType>(() => [
    new Date().getFullYear(),
    new Date().getMonth(),
    new Date().getDate(),
  ]);
  const [state, setState] = useState(() => {
    if (initDate && validateDate(initDate)) {
      return initDate;
    } else {
      return generateDate(calData);
    }
  });
  const [mode, setMode] = useState<modeType>('date');

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setState(e.target.value);
  };

  const handleClick = () => {
    setShow(true);
  };

  const ref = useRef<HTMLDivElement>(null);
  const [st, setst, unmount] = useStateAnimation(setShow, 200);
  useClickOutside(ref, () => setst(false));

  useEffect(() => {
    if (callback) callback(state);
  }, [state, callback]);

  const dayData = useMemo(() => {
    // 构建一个二维数组
    const data = getDateData(calData[0], calData[1], calData[2]);
    console.log(data);
    return data;
  }, [calData]);

  const MonthData = new Array(12).fill(1).map((_x, y) => y + 1);

  const startYear = getStartYear(calData);
  const yearMap = new Array(12).fill(1).map((_x, y) => startYear + y - 1);

  const handleBlur = () => {
    if (state !== generateDate(calData)) {
      // 如果相等， 说明是calData赋值上去的
      let res = validateDate(state); // 验证格式
      if (!res) {
        // 格式错误 用原来的
        setState(generateDate(calData));
      } else {
        // 否则计算新值
        let p = state.split('-');
        let newDate = new Date(parseInt(p[0]), parseInt(p[1]) - 1, parseInt(p[2]));
        const newCal: calDataType = [newDate.getFullYear(), newDate.getMonth(), newDate.getDate()];
        setCalData(newCal);
        setState(generateDate(newCal));
      }
    }
  };

  const render = useMemo(() => {
    const handleLeft = () => {
      let res: calDataType;
      if (mode === 'date') {
        res = changeCalData(-1, calData);
      } else if (mode === 'month') {
        res = changeCalYear(-1, calData);
      } else {
        res = changeCalYear(-10, calData);
      }
      setCalData(res);
    };

    const handleRight = () => {
      let res: calDataType;
      if (mode === 'date') {
        res = changeCalData(1, calData);
      } else if (mode === 'month') {
        res = changeCalYear(1, calData);
      } else {
        res = changeCalYear(10, calData);
      }
      setCalData(res);
    };

    const showMonth = `${calData[0]}年${calData[1] + 1}月`;
    if (!show) {
      unmount();
      return null;
    } else {
      const modeDay = (
        <table style={{ display: mode === 'date' ? 'block' : 'none' }}>
          <thead>
            <tr>
              <CalendarHeadItem>日</CalendarHeadItem>
              <CalendarHeadItem>一</CalendarHeadItem>
              <CalendarHeadItem>二</CalendarHeadItem>
              <CalendarHeadItem>三</CalendarHeadItem>
              <CalendarHeadItem>四</CalendarHeadItem>
              <CalendarHeadItem>五</CalendarHeadItem>
              <CalendarHeadItem>六</CalendarHeadItem>
            </tr>
          </thead>
          <tbody>
            {dayData.map((v, i) => (
              <CalendarDateRow key={i}>
                {v.map((k: DateItem, i) => (
                  <CalendarDate
                    key={i}
                    isonDay={k.isonDay}
                    isonMonth={k.isonMonth}
                    onClick={() => {
                      const origin = k.origin;
                      const newCal: calDataType = [
                        origin.getFullYear(),
                        origin.getMonth(),
                        origin.getDate(),
                      ];
                      setCalData(newCal);
                      setState(generateDate(newCal));
                      setst(false);
                    }}
                  >
                    {k.day}
                  </CalendarDate>
                ))}
              </CalendarDateRow>
            ))}
          </tbody>
        </table>
      );

      const modeMonth = (
        <MonthWrapper style={{ display: mode === 'month' ? 'flex' : 'none' }}>
          {MonthData.map((v, i) => {
            return (
              <MonthItem
                key={i}
                onClick={() => {
                  //获取当前月，与点击相减得差
                  let diff = v - calData[1] - 1;
                  let res = changeCalData(diff, calData);
                  setCalData(res);
                  setMode('date');
                }}
              >
                {v}月
              </MonthItem>
            );
          })}
        </MonthWrapper>
      );

      const modeYear = (
        <MonthWrapper style={{ display: mode === 'year' ? 'flex' : 'none' }}>
          {yearMap.map((v, i) => (
            <MonthItem
              key={i}
              toGrey={i === 0 || i === 11}
              onClick={() => {
                //获取当前月，与点击相减得差
                //获取选择的年与差值
                let diff = v - calData[0];
                let res = changeCalYear(diff, calData);
                setCalData(res);
                // 选完年之后，设置为月模式
                setMode('month');
              }}
            >
              {v}年
            </MonthItem>
          ))}
        </MonthWrapper>
      );

      return (
        <CalendarWarpper visible={st} delay={210}>
          <CalendarHeadWrapper>
            <BtnDiv>
              <Button size="small" style={btnStyle} onClick={() => handleLeft()}>
                <IconWrapper>
                  <Icon icon="arrowleft" />
                </IconWrapper>
              </Button>
            </BtnDiv>

            <BtnDiv>
              <span>
                <Bwrapper onClick={() => setMode('year')}>{`${calData[0]}年`}</Bwrapper>
                <Bwrapper
                  onClick={() => setMode('month')}
                  style={{
                    display: mode === 'date' ? 'inline-block' : 'none',
                  }}
                >{`${calData[1] + 1}月`}</Bwrapper>
              </span>
            </BtnDiv>
            <BtnDiv>
              <Button size="small" style={btnStyle} onClick={() => handleRight()}>
                <IconWrapper>
                  <Icon icon="arrowright" />
                </IconWrapper>
              </Button>
            </BtnDiv>
          </CalendarHeadWrapper>
          <div
            style={{
              width: '240px',
              display: 'flex',
              justifyContent: 'center',
            }}
          >
            {modeDay}
            {modeMonth}
            {modeYear}
          </div>
        </CalendarWarpper>
      );
    }
  }, [show, unmount, st, dayData, calData, mode]);

  return (
    <DatePickerWrapper ref={ref} style={style} className={classname}>
      <input
        aria-label="date picker"
        onBlur={handleBlur}
        value={state}
        onChange={handleChange}
        onClick={handleClick}
      ></input>
      <CalendarIcon>
        <Icon icon="calendar" />
      </CalendarIcon>
      {render}
    </DatePickerWrapper>
  );
}
